package cis.android.signlocker.signableview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;

public class SignableView extends View {
    // Vẽ
    private Path path;
    private Canvas canvas;
    private Bitmap bitmap;
    private Paint signPaint;
    private Paint bitmapPaint;
    private Paint pointPaint;
    private boolean showCatchedPoint;

    // Dữ liệu
    private long startTime;
    private ArrayList<SignDataRow> signData;
    private float mX;
    private float mY;

    public SignableView(Context context) {
        super(context);
        init();
    }

    public SignableView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public SignableView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        initData();
        initPainting();
        initEvent();
    }

    /**
     * Khởi tạo bút vẽ
     */
    private void initPainting() {
        path = new Path();
        bitmapPaint = new Paint(Paint.DITHER_FLAG);

        signPaint = new Paint();
        signPaint.setAntiAlias(true);
        signPaint.setDither(true);
        signPaint.setColor(Color.BLACK);
        signPaint.setStyle(Paint.Style.STROKE);
        signPaint.setStrokeJoin(Paint.Join.ROUND);
        signPaint.setStrokeCap(Paint.Cap.ROUND);
        signPaint.setStrokeWidth(5);

        pointPaint = new Paint();
        pointPaint.setAntiAlias(true);
        pointPaint.setColor(Color.BLUE);
        pointPaint.setDither(true);
        pointPaint.setStyle(Paint.Style.STROKE);
        pointPaint.setStrokeCap(Paint.Cap.ROUND);
        pointPaint.setStrokeJoin(Paint.Join.ROUND);
        pointPaint.setStrokeWidth(5);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        bitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);
        canvas = new Canvas(bitmap);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawBitmap(bitmap, 0, 0, bitmapPaint);
        canvas.drawPath(path, signPaint);

        // Vẽ các điểm bắt được
        if (showCatchedPoint)
            for (SignDataRow row : signData)
                canvas.drawCircle(row.getX(), row.getY(), 2, pointPaint);
    }

    /**
     * Khởi tạo dữ l iệu
     */
    private void initData() {
        startTime = 0;
        signData = new ArrayList<SignDataRow>();
    }

    /**
     * Khởi tạo sự kiện cho view
     */
    private void initEvent() {
        // Sự kiện chạm vào
        setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                return OnTouch(view, motionEvent);
            }
        });
    }

    /**
     * Xử lý khi chạm vào màn hình
     *
     * @param view
     * @param motionEvent
     * @return
     */
    private boolean OnTouch(View view, MotionEvent motionEvent) {
        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_DOWN:
                OnHandDown(view, motionEvent);
                break;
            case MotionEvent.ACTION_MOVE:
                OnMove(view, motionEvent);
                break;
            case MotionEvent.ACTION_UP:
                OnHandUp(view, motionEvent);
                break;
        }
        return true;
    }

    private void OnHandUp(View view, MotionEvent motionEvent) {
        // Tính thời gian
        long time = System.currentTimeMillis() - startTime;
        // Lấy vị trí chạm
        float positionX = motionEvent.getX();
        float positionY = motionEvent.getY();

        // Lưu dữ liệu
        signData.add(new SignDataRow(time, positionX, positionY));

        //  Thêm vào path
        path.lineTo(mX, mY);
        canvas.drawPath(path, signPaint);
        path.reset();

        invalidate();
    }

    private void OnMove(View view, MotionEvent motionEvent) {
        // Tính thời gian
        long time = System.currentTimeMillis() - startTime;
        // Lấy vị trí chạm
        float positionX = motionEvent.getX();
        float positionY = motionEvent.getY();

        //  Thêm vào path
        path.quadTo(mX, mY, (positionX + mX) / 2, (positionY + mY) / 2);

        // Lưu dữ liệu
        signData.add(new SignDataRow(time, positionX, positionY));

        mX = positionX;
        mY = positionY;
        invalidate();
    }

    private void OnHandDown(View view, MotionEvent motionEvent) {
        // Tính thời gian
        long time = 0;
        if (startTime == 0) {
            startTime = System.currentTimeMillis();
        } else {
            time = System.currentTimeMillis() - startTime;
        }

        // Lấy vị trí chạm
        float positionX = motionEvent.getX();
        float positionY = motionEvent.getY();

        // Thêm vào path
        path.reset();
        path.moveTo(positionX, positionY);

        // Lưu dữ liệu
        signData.add(new SignDataRow(time, positionX, positionY));

        mX = positionX;
        mY = positionY;
        invalidate();
    }

    /**
     * Xóa trắng bảng ký
     */
    public void clearSignature() {
        mX = 0;
        mY = 0;
        startTime = 0;
        signData = new ArrayList<SignDataRow>();
        path = new Path();
        bitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
        canvas = new Canvas(bitmap);
        invalidate();
        refreshDrawableState();
    }

    /**
     * Bật tắt hiển thị điểm bắt ược
     */
    public void toggleShowCatchedPoint() {
        showCatchedPoint = !showCatchedPoint;
        invalidate();
    }

    /**
     * Trả vễ dữ liệu ký
     *
     * @return dữ liệu dạng thời gian -> điểm chạm
     */
    public ArrayList<SignDataRow> getSignData() {
        return signData;
    }
}
